"""
文件管理核心模块
"""

from typing import List, Union, Optional, Dict
from pathlib import Path
import shutil
import os
from datetime import datetime

from ..utils.exceptions import FileConverterError, FileNotFoundError, PermissionError
from ..utils.logger import Logger


class FileManager:
    """文件管理器"""
    
    def __init__(self, logger: Optional[Logger] = None):
        self.logger = logger or Logger("FileManager")
    
    def validate_file_path(self, file_path: Union[str, Path], 
                          must_exist: bool = True, 
                          allowed_extensions: Optional[List[str]] = None) -> Path:
        """
        验证文件路径
        
        Args:
            file_path: 文件路径
            must_exist: 文件是否必须存在
            allowed_extensions: 允许的文件扩展名列表
            
        Returns:
            Path: 验证后的路径对象
            
        Raises:
            FileNotFoundError: 文件不存在
            FileConverterError: 文件格式不支持
        """
        file_path = Path(file_path)
        
        if must_exist and not file_path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        if allowed_extensions:
            if file_path.suffix.lower() not in [ext.lower() for ext in allowed_extensions]:
                raise FileConverterError(f"不支持的文件格式: {file_path.suffix}")
        
        return file_path
    
    def create_backup(self, file_path: Union[str, Path], backup_dir: Optional[Union[str, Path]] = None) -> Path:
        """
        创建文件备份
        
        Args:
            file_path: 原文件路径
            backup_dir: 备份目录，默认为原文件目录下的backup子目录
            
        Returns:
            Path: 备份文件路径
        """
        file_path = Path(file_path)
        
        if not file_path.exists():
            raise FileNotFoundError(f"要备份的文件不存在: {file_path}")
        
        if backup_dir is None:
            backup_dir = file_path.parent / "backup"
        else:
            backup_dir = Path(backup_dir)
        
        backup_dir.mkdir(parents=True, exist_ok=True)
        
        # 生成备份文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_name = f"{file_path.stem}_{timestamp}{file_path.suffix}"
        backup_path = backup_dir / backup_name
        
        try:
            shutil.copy2(file_path, backup_path)
            self.logger.info(f"创建备份文件: {backup_path}")
            return backup_path
        except Exception as e:
            self.logger.error(f"创建备份失败: {e}")
            raise FileConverterError(f"创建备份失败: {e}")
    
    def ensure_directory(self, dir_path: Union[str, Path]) -> Path:
        """
        确保目录存在
        
        Args:
            dir_path: 目录路径
            
        Returns:
            Path: 目录路径对象
        """
        dir_path = Path(dir_path)
        try:
            dir_path.mkdir(parents=True, exist_ok=True)
            return dir_path
        except Exception as e:
            raise PermissionError(f"无法创建目录: {dir_path}, 错误: {e}")
    
    def get_safe_filename(self, filename: str, max_length: int = 255) -> str:
        """
        获取安全的文件名（移除非法字符）
        
        Args:
            filename: 原文件名
            max_length: 最大长度
            
        Returns:
            str: 安全的文件名
        """
        # 移除或替换非法字符
        illegal_chars = '<>:"/\\|?*'
        safe_name = filename
        
        for char in illegal_chars:
            safe_name = safe_name.replace(char, '_')
        
        # 移除前后空格和点
        safe_name = safe_name.strip(' .')
        
        # 限制长度
        if len(safe_name) > max_length:
            name_part = Path(safe_name).stem
            ext_part = Path(safe_name).suffix
            max_name_length = max_length - len(ext_part)
            safe_name = name_part[:max_name_length] + ext_part
        
        # 确保不为空
        if not safe_name:
            safe_name = "untitled"
        
        return safe_name
    
    def get_unique_filename(self, file_path: Union[str, Path]) -> Path:
        """
        获取唯一的文件名（如果文件已存在，添加数字后缀）
        
        Args:
            file_path: 文件路径
            
        Returns:
            Path: 唯一的文件路径
        """
        file_path = Path(file_path)
        
        if not file_path.exists():
            return file_path
        
        counter = 1
        while True:
            new_name = f"{file_path.stem}_{counter}{file_path.suffix}"
            new_path = file_path.parent / new_name
            
            if not new_path.exists():
                return new_path
            
            counter += 1
            
            # 防止无限循环
            if counter > 9999:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                new_name = f"{file_path.stem}_{timestamp}{file_path.suffix}"
                return file_path.parent / new_name
    
    def get_file_info(self, file_path: Union[str, Path]) -> Dict:
        """
        获取文件信息
        
        Args:
            file_path: 文件路径
            
        Returns:
            Dict: 文件信息字典
        """
        file_path = Path(file_path)
        
        if not file_path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        try:
            stat = file_path.stat()
            return {
                'name': file_path.name,
                'stem': file_path.stem,
                'suffix': file_path.suffix,
                'size': stat.st_size,
                'size_mb': round(stat.st_size / (1024 * 1024), 2),
                'created': datetime.fromtimestamp(stat.st_ctime),
                'modified': datetime.fromtimestamp(stat.st_mtime),
                'is_file': file_path.is_file(),
                'is_dir': file_path.is_dir(),
                'absolute_path': str(file_path.resolve())
            }
        except Exception as e:
            self.logger.error(f"获取文件信息失败: {e}")
            raise FileConverterError(f"获取文件信息失败: {e}")
    
    def cleanup_temp_files(self, temp_dir: Union[str, Path], max_age_hours: int = 24):
        """
        清理临时文件
        
        Args:
            temp_dir: 临时目录
            max_age_hours: 最大保留时间（小时）
        """
        temp_dir = Path(temp_dir)
        
        if not temp_dir.exists():
            return
        
        current_time = datetime.now()
        cleaned_count = 0
        
        try:
            for file_path in temp_dir.rglob('*'):
                if file_path.is_file():
                    file_age = current_time - datetime.fromtimestamp(file_path.stat().st_mtime)
                    
                    if file_age.total_seconds() > max_age_hours * 3600:
                        try:
                            file_path.unlink()
                            cleaned_count += 1
                        except Exception as e:
                            self.logger.warning(f"删除临时文件失败: {file_path}, 错误: {e}")
            
            self.logger.info(f"清理了 {cleaned_count} 个临时文件")
            
        except Exception as e:
            self.logger.error(f"清理临时文件失败: {e}")
    
    def get_available_space(self, path: Union[str, Path]) -> int:
        """
        获取可用磁盘空间（字节）
        
        Args:
            path: 路径
            
        Returns:
            int: 可用空间字节数
        """
        try:
            if os.name == 'nt':  # Windows
                import ctypes
                free_bytes = ctypes.c_ulonglong(0)
                ctypes.windll.kernel32.GetDiskFreeSpaceExW(
                    ctypes.c_wchar_p(str(path)),
                    ctypes.pointer(free_bytes),
                    None,
                    None
                )
                return free_bytes.value
            else:  # Unix/Linux
                statvfs = os.statvfs(str(path))
                return statvfs.f_frsize * statvfs.f_bavail
        except Exception as e:
            self.logger.warning(f"获取磁盘空间失败: {e}")
            return 0
